/*
 * Copyright 2002-2017 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.springframework.aop;

import org.aopalliance.aop.Advice;

/**
 * Base interface holding AOP <b>advice</b> (action to take at a joinpoint)
 * and a filter determining the applicability of the advice (such as
 * a pointcut). <i>This interface is not for use by Spring users, but to
 * allow for commonality in support for different types of advice.</i>
 *
 * <p>Spring AOP is based around <b>around advice</b> delivered via method
 * <b>interception</b>, compliant with the AOP Alliance interception API.
 * The Advisor interface allows support for different types of advice,
 * such as <b>before</b> and <b>after</b> advice, which need not be
 * implemented using interception.
 *
 * @author Rod Johnson
 * @author Juergen Hoeller
 */
/*
1. 总结 表示一个切面（aspect）的组成部分。
	Advisor = advice通知 + pointcut切点	(注意：切点部分在更具体的子接口中定义)
	它结合了通知（advice）和切入点（pointcut）的功能，定义了在连接点（joinpoint）处执行的动作以及该动作适用的条件。
	Advisor 接口本身不是供最终用户直接使用的，而是为支持不同类型的切面提供通用性。
2. 内部成员解释
	EMPTY_ADVICE: 一个空的 Advice 实例，当尚未配置适当的通知时，可作为 getAdvice() 方法的返回值占位符。
	getAdvice(): 返回此切面的通知部分。通知可以是拦截器、前置通知、异常通知等。
	isPerInstance(): 返回此通知是否与特定实例相关联，或者是否与从同一 Spring bean 工厂获取的所有被通知类实例共享。



3 相关的接口和类
Advisor		AOP 切面的基本抽象，是最顶层接口，定义了最基本的方法 getAdvice() 和 isPerInstance()
├── PointcutAdvisor	扩展 Advisor，添加切点概念，增加了 getPointcut() 方法，用于确定通知的应用位置，用于常规的方法拦截场景
│   ├── StaticMethodMatcherPointcutAdvisor	用于将一个静态方法匹配器切点（StaticMethodMatcherPointcut）与一个通知（Advice）组合，支持基于方法名、正则表达式等静态条件进行匹配
│   ├── AspectJPointcutAdvisor	专门用于支持 AspectJ 表达式的切点和通知的组合。（可以解析并执行如 execution(* com.example.service.*.*(..)) 这样的复杂切点表达式。）
│   ├── InstantiationModelAwarePointcutAdvisor 一种特殊的 PointcutAdvisor，支持在代理对象创建时根据实例化模型决定是否应用通知。（主要用于处理需要在目标类实例化阶段就介入的场景，比如通过 @DeclareParents 实现引介（Introduction）功能。）
│	│	 └── InstantiationModelAwarePointcutAdvisorImpl
│   └── AbstractPointcutAdvisor	PointcutAdvisor的抽象基类实现
│	     └── AbstractGenericPointcutAdvisor		AbstractPointcutAdvisor的基础上，允许设置一个Advice实例
│	         ├── DefaultPointcutAdvisor		 最通用的PointcutAdvisor实现，可以组合任意的Pointcut和Advice
│	         ├── NameMatchMethodPointcutAdvisor	基于方法名匹配的PointcutAdvisor，简单场景下根据方法名进行拦截
│	         ├── RegexpMethodPointcutAdvisor	基于正则表达式的PointcutAdvisor，需要复杂方法名匹配的场景
│	         └── AspectJExpressionPointcutAdvisor	基于AspectJ表达式的PointcutAdvisor，与AspectJ集成，使用强大的切点表达式
└── IntroductionAdvisor	专门用于引介（Introduction）的Advisor，用于向现有类引入新的接口和实现，而非拦截方法调用，实现mixin功能，给目标类添加新接口
     ├── DeclareParentsAdvisor	用于声明父类型的IntroductionAdvisor，通常由AspectJ的@DeclareParents注解创建，与AspectJ的引介功能集成
     └── DefaultIntroductionAdvisor		默认的IntroductionAdvisor实现，可以引入一个或多个接口及其实现


实现类
	DefaultPointcutAdvisor: 最常用的 PointcutAdvisor 实现，可以将任何 Pointcut 和任何 Advice 组合在一起。
	DefaultIntroductionAdvisor: 最常用的 IntroductionAdvisor 实现，用于引入新的接口和实现。
	AspectJExpressionPointcutAdvisor: 基于 AspectJ 表达式的切点通知器。
相关类和接口的区别
	PointcutAdvisor: 处理方法拦截，方法级别的AOP增强，添加了 getPointcut() 方法，用于返回与此通知器关联的切点。
	IntroductionAdvisor: 处理类型引介，为现有类型添加新接口，专门用于引入新的接口和实现，通常用于实现 mixin 功能。




4. 使用场景
	Advisor 接口主要用于 Spring AOP 框架内部，用于表示切面的组成部分。它通常在以下场景中使用：
	创建自定义切面时，需要实现 Advisor 接口或其子接口。
	在 Spring 配置中定义切面时，框架会自动创建相应的 Advisor 实例。
	在编程式创建 AOP 代理时，需要手动创建和配置 Advisor 实例。

5. 实际代码应用示例

// 创建一个前置通知
MethodBeforeAdvice advice = new MethodBeforeAdvice() {
    @Override
    public void before(Method method, Object[] args, Object target) throws Throwable {
        System.out.println("Before method: " + method.getName());
    }
};

// 创建一个切点
Pointcut pointcut = new StaticMethodMatcherPointcut() {
    @Override
    public boolean matches(Method method, Class<?> targetClass) {
        return method.getName().startsWith("get");
    }
};

// 创建一个切面通知器
PointcutAdvisor advisor = new DefaultPointcutAdvisor(pointcut, advice);

// 使用 ProxyFactory 创建代理
ProxyFactory proxyFactory = new ProxyFactory(targetObject);
proxyFactory.addAdvisor(advisor);
Object proxy = proxyFactory.getProxy();


 */
public interface Advisor {

	/**
	 * Common placeholder for an empty {@code Advice} to be returned from
	 * {@link #getAdvice()} if no proper advice has been configured (yet).
	 * @since 5.0
	 */
	Advice EMPTY_ADVICE = new Advice() {};


	/**
	 * Return the advice part of this aspect. An advice may be an
	 * interceptor, a before advice, a throws advice, etc.
	 * @return the advice that should apply if the pointcut matches
	 * @see org.aopalliance.intercept.MethodInterceptor
	 * @see BeforeAdvice
	 * @see ThrowsAdvice
	 * @see AfterReturningAdvice
	 */
	Advice getAdvice();

	/**
	 * Return whether this advice is associated with a particular instance
	 * (for example, creating a mixin) or shared with all instances of
	 * the advised class obtained from the same Spring bean factory.
	 * <p><b>Note that this method is not currently used by the framework.</b>
	 * Typical Advisor implementations always return {@code true}.
	 * Use singleton/prototype bean definitions or appropriate programmatic
	 * proxy creation to ensure that Advisors have the correct lifecycle model.
	 * @return whether this advice is associated with a particular target instance
	 */
	boolean isPerInstance();

}
